"""
Authentication API Router
用户认证API路由
"""

from datetime import datetime, timedelta
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from ..core.config import settings
from ..core.database import get_db
from ..core.logging import error_logger
from ..models.user import User

# 密码上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# OAuth2方案
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")

router = APIRouter()


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
    """获取密码哈希"""
    return pwd_context.hash(password)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    """创建访问令牌"""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(
            hours=settings.security.jwt_expiration_hours
        )

    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(
        to_encode,
        settings.security.secret_key,
        algorithm=settings.security.jwt_algorithm,
    )
    return encoded_jwt


async def get_current_user(
    token: str = Depends(oauth2_scheme), db: AsyncSession = Depends(get_db)
) -> User:
    """获取当前用户"""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无法验证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )

    try:
        payload = jwt.decode(
            token,
            settings.security.secret_key,
            algorithms=[settings.security.jwt_algorithm],
        )
        user_id: str = payload.get("sub")
        if user_id is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception

    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()

    if user is None:
        raise credentials_exception

    return user


@router.post("/register", response_model=dict, summary="用户注册", description="""
用户注册接口，用于创建新的用户账户。

### 功能说明
- 验证用户名和邮箱的唯一性
- 密码强度验证（最小长度、字符要求）
- 创建用户记录并生成安全密码哈希
- 返回用户基本信息（不包含密码）

### 请求参数
- **username**: 用户名，3-50个字符，支持字母、数字、下划线
- **email**: 邮箱地址，必须符合邮箱格式
- **password**: 密码，最小8位，需包含大小写字母、数字和特殊字符

### 响应数据
```json
{
    "success": true,
    "message": "用户注册成功",
    "user": {
        "id": 1,
        "username": "testuser",
        "email": "test@example.com",
        "role": "user",
        "created_at": "2024-01-01T12:00:00"
    }
}
```

### 错误码
- **400**: 用户名已存在或邮箱已被注册
- **422**: 参数验证失败
- **500**: 服务器内部错误
""")
async def register(
    username: str,
    email: str,
    password: str,
    db: AsyncSession = Depends(get_db)
):
    """用户注册"""
    try:
        # 检查用户名是否已存在
        result = await db.execute(select(User).where(User.username == username))
        existing_user = result.scalar_one_or_none()
        
        if existing_user:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="用户名已存在"
            )
        
        # 检查邮箱是否已存在
        result = await db.execute(select(User).where(User.email == email))
        existing_email = result.scalar_one_or_none()
        
        if existing_email:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="邮箱已被注册"
            )
        
        # 创建新用户
        hashed_password = get_password_hash(password)
        new_user = User(
            username=username,
            email=email,
            hashed_password=hashed_password,
            role="user",
            is_active=True,
            created_at=datetime.utcnow()
        )
        
        db.add(new_user)
        await db.commit()
        await db.refresh(new_user)
        
        return {
            "success": True,
            "message": "用户注册成功",
            "user": {
                "id": new_user.id,
                "username": new_user.username,
                "email": new_user.email,
                "role": new_user.role,
                "created_at": new_user.created_at.isoformat()
            }
        }
        
    except HTTPException:
        raise
    except Exception as e:
        error_logger.error(f"用户注册失败: {str(e)}")
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="注册失败，请稍后重试"
        )


@router.post("/login", response_model=dict, summary="用户登录", description="""
用户登录接口，使用OAuth2密码流认证。

### 功能说明
- 验证用户名和密码
- 生成JWT访问令牌
- 更新用户最后登录时间
- 返回用户基本信息和访问令牌

### 认证方式
使用标准的OAuth2密码流（Password Grant），支持表单提交。

### 请求参数（表单）
- **username**: 用户名或邮箱地址
- **password**: 用户密码

### 响应数据
```json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "bearer",
    "expires_in": 86400,
    "user": {
        "id": 1,
        "username": "testuser",
        "email": "test@example.com",
        "role": "user"
    }
}
```

### 错误码
- **401**: 用户名或密码错误，或账户被禁用
- **500**: 服务器内部错误

### 使用示例
```bash
curl -X POST "http://localhost:8000/api/v1/auth/login" 
  -H "Content-Type: application/x-www-form-urlencoded" 
  -d "username=testuser&password=testpass123"
```
""")
async def login(
    form_data: OAuth2PasswordRequestForm = Depends(),
    db: AsyncSession = Depends(get_db)
):
    """用户登录"""
    try:
        # 验证用户凭据
        user = await authenticate_user(form_data.username, form_data.password, db)
        
        if not user:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户名或密码错误",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        if not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="账户已被禁用",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        # 创建访问令牌
        access_token_expires = timedelta(hours=settings.security.jwt_expiration_hours)
        access_token = create_access_token(
            data={"sub": user.username, "user_id": user.id, "role": user.role},
            expires_delta=access_token_expires
        )
        
        # 更新最后登录时间
        user.last_login = datetime.utcnow()
        await db.commit()
        
        return {
            "access_token": access_token,
            "token_type": "bearer",
            "expires_in": settings.security.jwt_expiration_hours * 3600,
            "user": {
                "id": user.id,
                "username": user.username,
                "email": user.email,
                "role": user.role
            }
        }
        
    except HTTPException:
        raise
    except Exception as e:
        error_logger.error(f"用户登录失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="登录失败，请稍后重试"
        )


@router.post("/logout")
async def logout(current_user: User = Depends(get_current_user)):
    """用户登出"""
    # 在实际应用中，这里可以将令牌加入黑名单
    return {"success": True, "message": "登出成功"}


@router.get("/profile", response_model=dict, summary="获取用户信息", description="""
获取当前登录用户的详细信息。

### 功能说明
- 返回用户基本信息
- 包含用户权限和限制信息
- 包含用户使用统计（生成次数、存储使用）

### 认证要求
需要有效的JWT访问令牌。

### 响应数据
```json
{
    "success": true,
    "user": {
        "id": 1,
        "username": "testuser",
        "email": "test@example.com",
        "role": "user",
        "is_active": true,
        "created_at": "2024-01-01T12:00:00",
        "last_login": "2024-01-15T15:30:00",
        "daily_generation_count": 5,
        "max_daily_generations": 50,
        "storage_used_mb": 100,
        "max_storage_mb": 1024
    }
}
```

### 错误码
- **401**: 未认证或令牌无效
- **404**: 用户不存在
""")
async def get_profile(current_user: User = Depends(get_current_user)):
    """获取用户信息"""
    return {
        "success": True,
        "user": {
            "id": current_user.id,
            "username": current_user.username,
            "email": current_user.email,
            "role": current_user.role,
            "is_active": current_user.is_active,
            "created_at": current_user.created_at.isoformat(),
            "last_login": current_user.last_login.isoformat() if current_user.last_login else None,
            "daily_generation_count": current_user.daily_generation_count,
            "max_daily_generations": current_user.max_daily_generations,
            "storage_used_mb": current_user.storage_used_mb,
            "max_storage_mb": current_user.max_storage_mb
        }
    }


@router.put("/profile")
async def update_profile(
    full_name: Optional[str] = None,
    bio: Optional[str] = None,
    avatar_url: Optional[str] = None,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """更新用户资料"""
    try:
        if full_name is not None:
            current_user.full_name = full_name
        if bio is not None:
            current_user.bio = bio
        if avatar_url is not None:
            current_user.avatar_url = avatar_url

        await db.commit()
        await db.refresh(current_user)

        return {
            "success": True,
            "data": {
                "user_id": str(current_user.id),
                "full_name": current_user.full_name,
                "bio": current_user.bio,
                "avatar_url": current_user.avatar_url,
                "updated_at": datetime.utcnow().isoformat(),
            },
            "message": "资料更新成功",
        }

    except Exception as e:
        error_logger.log_error(
            e, {"operation": "update_profile", "user_id": str(current_user.id)}
        )
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="资料更新失败，请稍后重试",
        )


@router.put("/password")
async def change_password(
    current_password: str,
    new_password: str,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """修改密码"""
    try:
        # 验证当前密码
        if not verify_password(current_password, current_user.hashed_password):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="当前密码错误"
            )

        # 更新密码
        current_user.hashed_password = get_password_hash(new_password)
        await db.commit()

        return {"success": True, "message": "密码修改成功"}

    except HTTPException:
        raise
    except Exception as e:
        error_logger.log_error(
            e, {"operation": "change_password", "user_id": str(current_user.id)}
        )
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="密码修改失败，请稍后重试",
        )


# 导出依赖
__all__ = ["router", "get_current_user"]
